﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using frag_boardgame;
using DataBase;
using System.Threading;
using System.Timers;

namespace GameService
{
    public class GameManager
    {

        public Dictionary<string, UserInfo> users = new Dictionary<string, UserInfo>();
        public Dictionary<string, Room> rooms = new Dictionary<string, Room>();
        public int NumOfGuests = 0;
        public bool isDisconnectionDetectoron = false;
        public long? currentUserFacebookUid;


        private void InitilizeGuest(string name)
        {
            if (users.Count == 0)
                NumOfGuests = 1;
            InitilizeLobby(name);
        }
        private void InitilizeUser(string name)
        {   
            if (users.Count == 0)
                NumOfGuests = 0;
            InitilizeLobby(name);

        }
        private void InitilizeLobby(string name)
        {
            //CheckClients(false);
            UserInfo info = new UserInfo();
            info.config = new PlayerConfiguration();
            info.config.Name = name;
            info.Uid = currentUserFacebookUid;

            users[name] = info;

            //if (!lobby.isDisconnectionDetectoron)
            //{
            //    timer.Elapsed += new ElapsedEventHandler(DetectDisconnection);
            //    timer.Interval = DETECT_DISCONNECTION_TIME;
            //    timer.Enabled = true;
            //    lobby.isDisconnectionDetectoron = true;
            //}
        }

        //private void DetectDisconnection(object source, ElapsedEventArgs e)
        //{
        //    CheckClients(true);
        //}
        public void RemoveUser(string user)
        {
            users.Remove(user);
        }
        //the method gets a name of a user that has disconnented and update all the other users about it.
        private void UpdateClients(string name)
        {
            foreach (UserInfo user in users.Values)
            {
                user.AddMessage(name + " disconnected from server", "Server");
            }
        }

        #region ILobby Members



        public RoomInfo[] GetRooms()
        {
            var x = from room in rooms
                    select room.Value.Info;
            return x.ToArray();
        }

        public RoomInfo CreateRoom(string name, GameConfiguration config)
        {
            Board board;
            
            if (rooms.ContainsKey(name))
            {
                throw new ArgumentException("name '" + name + "' already exists");
            }

            if (config.BoardName != null)
            {
                DBAdapter dba = new DBAdapter();
                board = dba.getBoard(config.BoardName);
                if (board == null)
                    throw new ArgumentException("board '" + config.BoardName + "' does not exists");
            }
            else
            {
                board = new Board(config.Rows, config.Cols);
            }

            CrateRandomWalls(board);

            Room room = new Room();
            room.Info.name = name;
            room.Info.nPlayers = 0;
            room.Info.config = new Configuraion(config);
            room.Info.config.SetBoard(board);
            rooms.Add(name, room);

            return room.Info;
        }

        private void CrateRandomWalls(Board board)
        {
            int wallsNumber = board.Height * board.Width / 3;
            Random random = new Random();
            for (int i = 1; i <= wallsNumber; i++)
            {
                int row = random.Next(board.Height - 1);
                int col = random.Next(board.Width - 1);
                int type = random.Next(2);

                if (type == 0)
                    board.GetSquare(row, col).AddWall(SquareWalls.Up);

                if (type == 1)
                    board.GetSquare(row, col).AddWall(SquareWalls.Right);
            }

            for (int j = 0; j < board.Width; j++)
            {
                board.GetSquare(0, j).AddWall(SquareWalls.Down);
                board.GetSquare(board.Height - 1, j).AddWall(SquareWalls.Up);
            }

            for (int i = 0; i < board.Height; i++)
            {
                board.GetSquare(i, 0).AddWall(SquareWalls.Left);
                board.GetSquare(i,board.Width-1).AddWall(SquareWalls.Right);
            }
        }

        public List<string> GetPlayerHistory(string userName)
        {
            List<String> playerHistory;
            try
            {
                playerHistory = new DBAdapter().getPlayerHistory(userName);
            }
            catch (Exception e)
            {
                playerHistory = new List<string>();
            }
            return playerHistory; 

        }

        public List<string> GetPresetBoardsList()
        {
            List<String> boards;
            try
            {
                boards = new DBAdapter().getBoardsList();
            }
            catch (Exception e)
            {
                boards = new List<string>() ;
            }
            return boards;
        }


        public AuthenticationResult Authenticate(string name, string password)
        {
            DBAdapter dba = new DBAdapter();

            if (dba.checkUsername(name)==null)
                return AuthenticationResult.IncorrectUserName;
            if (dba.checkUserPassword(name, password) == null)
                return AuthenticationResult.IncorrectPassword;
            if (users.ContainsKey(name))
                return AuthenticationResult.UserAlreadyLoggedIn;


            InitilizeUser(name);

            return AuthenticationResult.Succeed;
            

 
        }

        public AuthenticationResult AuthenticateFacebook(string name)
        {
            DBAdapter dba = new DBAdapter();
            dba.addAccount(name, "facebook", "");
            return Authenticate(name, "facebook");
        }

        
        public string Guest_Connection()
        {
            
            NumOfGuests++;
            string name = "Guest" + NumOfGuests;
            InitilizeGuest(name);
           
            return name;
        }

        public string Guest_Connection(string name)
        {
            InitilizeGuest(name);
            return name;
        }



        public AddingNewUserResult AddUser(string name, string password, string email)
        {
            DBAdapter dba = new DBAdapter();

            if (!DBLibrary.checkEmailValidity(email))
                return AddingNewUserResult.IncorrectEmail;
            if (!dba.isUserNameAvailable(name))
                return AddingNewUserResult.UserExist;
            if (dba.addAccount(name, password, email))
            {
                InitilizeUser(name);
                return  AddingNewUserResult.Succeed;
            }
            else
                return AddingNewUserResult.UnknownError;
        }


        public int GetPlayerScore(string name)
        {
            DBAdapter db = new DBAdapter();
            return db.getPlayerScore(name);
        }

        public UserInfo GetUserInfo(string name)
        {
            UserInfo res;
            if (users.TryGetValue(name, out res))
                return res;
            else
                return null;
        }

        #endregion


        public JoinRoomResult JoinRoom(string roomName, string userName)
        {
            UserInfo userInfo;
            Room room;
            try
            {
                userInfo = users[userName];
                
            }
            catch (KeyNotFoundException ex)
            {
                return JoinRoomResult.UserNotFound;
            }

            try
            {
                room = rooms[roomName];
            }
            catch (KeyNotFoundException ex)
            {

                return JoinRoomResult.RoomNotFound;
            }

            if (room.Info.nPlayers == room.Info.config.NumberOfPlayers)
                return JoinRoomResult.RoomIsFull;
            if (room.IsPlaying == true)
                return JoinRoomResult.GameStarted;

           


            room.Users[userName] = userInfo;
            room.Info.nPlayers++;
            return JoinRoomResult.Succeed;
        }


        public void LeaveRoom(Room room, UserInfo userInfo)
        {
            room.Users.Remove(userInfo.config.Name);
            room.Info.nPlayers--;
        }

        public void CalculateNewScore(string name, Room room)
        {
            

            int ScroeSum = 0;
            foreach (UserInfo user in room.Users.Values)
            {


                string username = user.config.Name;
                if (!username.ToLower().StartsWith("guest") && !(username == name))
                    ScroeSum += GetPlayerScore(user.config.Name);
                
            }

            IncresePlayerScore(name, ScroeSum / 4);
            
        }
        private void IncresePlayerScore(string name, int score)
        {
            //Need to connecnt to DB.   
            //The method get's user name and a score and adds the scroe to his current score.
            DBAdapter dba = new DBAdapter();
            dba.addScoreToPlayer(name, score);

        }
        

    }

}
